﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using System.Windows.Forms;
using System.Diagnostics;
using Microsoft.Win32;

namespace GPU_Performance_Manager
{
    public partial class GPU_Performance_Manager : Form
    {
        INIFile iniFile = new INIFile("GPU Performance Manager.ini", false, true);
        CancellationTokenSource cancelToken = new CancellationTokenSource();
        ManualResetEvent manualResetEvent = new ManualResetEvent(false);
        Process[] currentProcessesList = null;
        List<string> application3DList = new List<string>();
        GlobalHotKey globalHotKeyStartMonitoring;
        GlobalHotKey globalHotKeyStopMonitoring;
        GlobalHotKey globalHotKey2D;
        GlobalHotKey globalHotKey3D;
        int globalHotKeyStartMonitoringKeyData;
        int globalHotKeyStopMonitoringKeyData;
        int globalHotKey2DKeyData;
        int globalHotKey3DKeyData;
        int pollingRate;
        string processName;
        string file2D;
        string file3D;
        bool launchMonitoringAtStartup;
        bool closeToSystemTray;
        bool openToSystemTray;
        bool monitoringRunning = false;
        bool applicationNeeds3DProfile = false;
        bool currentProfileIs3D = false;

        public bool OpenToSystemTray { get { return openToSystemTray; } }
        
        public GPU_Performance_Manager()
        {
            InitializeComponent();
            SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);

            getSettingsFromIni();

            textBox2D.ReadOnly = false;
            textBox3D.ReadOnly = false;
            buttonStartMonitoring.Enabled = true;
            buttonStopMonitoring.Enabled = false;
            buttonRemove3D.Enabled = false;

            if (launchMonitoringAtStartup == true)
                launchMonitoring();

            validateAndRegisterHotKey(globalHotKeyStartMonitoring);
            validateAndRegisterHotKey(globalHotKeyStopMonitoring);
            validateAndRegisterHotKey(globalHotKey2D);
            validateAndRegisterHotKey(globalHotKey3D);
        }

        private void monitorProcesses()
        {
            writeTextBoxLog("Launching monitoring...");
            buttonStartMonitoring.Enabled = false;
            buttonStopMonitoring.Enabled = true;
            textBox2D.ReadOnly = true;
            textBox3D.ReadOnly = true;
            buttonBrowse2D.Enabled = false;
            buttonBrowse3D.Enabled = false;
            monitoringRunning = true;

            Task monitorProcesses = Task.Factory.StartNew(() =>
            {
                try
                {
                    load2DProfile();
                    while (true)
                    {
                        manualResetEvent.WaitOne(pollingRate);

                        if (cancelToken.Token.IsCancellationRequested)
                            cancelToken.Token.ThrowIfCancellationRequested();

                        currentProcessesList = Process.GetProcesses();

                        applicationNeeds3DProfile = false;
                        foreach (Process process in currentProcessesList)
                        {
                            if (application3DList.Contains(process.ProcessName.ToUpperInvariant() + ".EXE"))
                            {
                                applicationNeeds3DProfile = true;
                                processName = process.ProcessName + ".exe";
                            }
                        }

                        if (applicationNeeds3DProfile == true && currentProfileIs3D == false)
                            load3DProfile(processName);
                        else if (applicationNeeds3DProfile == false && currentProfileIs3D == true)
                            load2DProfile();
                    }
                }
                catch (OperationCanceledException)
                {
                    textBoxLog.Invoke((Action)delegate { writeTextBoxLog("Stopping monitoring..."); });
                }
                catch (Exception ex)
                {
                    textBoxLog.Invoke((Action)delegate { writeTextBoxLog("There was an error, stopping monitoring..."); });
                    this.Invoke((Func<DialogResult>)delegate { return MessageBox.Show(this, "ERROR: " + ex.Message, "Monitoring error", MessageBoxButtons.OK, MessageBoxIcon.Error); });
                }
                // ContinueWith is used to sync the UI when the task completes
            }, cancelToken.Token).ContinueWith((result) =>
            {
                // Do stuff, like updating the main UI
                buttonStartMonitoring.Enabled = true;
                buttonStopMonitoring.Enabled = false;
                textBox2D.ReadOnly = false;
                textBox3D.ReadOnly = false;
                buttonBrowse2D.Enabled = true;
                buttonBrowse3D.Enabled = true;
                monitoringRunning = false;
            }, new CancellationTokenSource().Token, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
        }

        private void signalStartMonitoring()
        {
            cancelToken = new CancellationTokenSource();
            manualResetEvent.Reset();
        }

        private void signalStopMonitoring()
        {
            cancelToken.Cancel();
            manualResetEvent.Set();
        }

        private void writeTextBoxLog(string line)
        {
            textBoxLog.AppendText(DateTime.Now.ToString("HH:mm:ss.fff") + " - " + line + Environment.NewLine);
        }

        private void load2DProfile()
        {
            try
            {
                Process.Start(file2D);
                textBoxLog.Invoke((Action)delegate { writeTextBoxLog("2D profile loaded"); });
                currentProfileIs3D = false;
            }
            catch (Exception ex)
            {
                if (this.Visible == false || this.WindowState == FormWindowState.Minimized)
                    showForm();
                signalStopMonitoring();
                this.Invoke((Func<DialogResult>)delegate { return MessageBox.Show(this, "ERROR: " + ex.Message, "2D file error", MessageBoxButtons.OK, MessageBoxIcon.Error); });
            }
        }

        private void load3DProfile(string application)
        {
            try
            {
                Process.Start(file3D);
                textBoxLog.Invoke((Action)delegate { writeTextBoxLog("3D profile loaded for " + application); });
                currentProfileIs3D = true;
            }
            catch (Exception ex)
            {
                if (this.Visible == false || this.WindowState == FormWindowState.Minimized)
                    showForm();
                signalStopMonitoring();
                this.Invoke((Func<DialogResult>)delegate { return MessageBox.Show(this, "ERROR: " + ex.Message, "3D file error", MessageBoxButtons.OK, MessageBoxIcon.Error); });
            }
        }

        private void load3DProfile()
        {
            try
            {
                Process.Start(file3D);
                textBoxLog.Invoke((Action)delegate { writeTextBoxLog("3D profile loaded"); });
                currentProfileIs3D = true;
            }
            catch (Exception ex)
            {
                if (this.Visible == false || this.WindowState == FormWindowState.Minimized)
                    showForm();
                signalStopMonitoring();
                this.Invoke((Func<DialogResult>)delegate { return MessageBox.Show(this, "ERROR: " + ex.Message, "3D file error", MessageBoxButtons.OK, MessageBoxIcon.Error); });
            }
        }

        private void launchMonitoring()
        {
            if (File.Exists(file2D) && File.Exists(file3D))
                monitorProcesses();
            else
                writeTextBoxLog("Invalid 2D or 3D file, please select valid files before starting monitoring");
        }

        private void validateAndRegisterHotKey(GlobalHotKey globalHotKey)
        {
            if (globalHotKey != null)
            {
                bool result = globalHotKey.Register();
                if (result == false)
                    MessageBox.Show(this, "Error when registering hotkey: " + convertKeysToString(globalHotKey.KeyData), "Hotkey error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        private void unregisterHotKey(GlobalHotKey globalHotKey)
        {
            if (globalHotKey != null)
            {
                bool result = globalHotKey.Unregister();
                if (result == false)
                    MessageBox.Show(this, "Error when unregistering hotkey: " + convertKeysToString(globalHotKey.KeyData), "Hotkey error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        private string convertKeysToString(Keys keyData)
        {
            bool hasControl = false;
            bool hasAlt = false;
            bool hasShift = false;
            string conversion = String.Empty;
            KeysConverter converter = new KeysConverter();

            if ((keyData & Keys.Control) == Keys.Control)
            {
                hasControl = true;
                conversion = "Ctrl";
            }
            if ((keyData & Keys.Alt) == Keys.Alt)
            {
                hasAlt = true;
                if (hasControl == true)
                    conversion = conversion + "+Alt";
                else
                    conversion = "Alt";
            }
            if ((keyData & Keys.Shift) == Keys.Shift)
            {
                hasShift = true;
                if (hasControl == true || hasAlt == true)
                    conversion = conversion + "+Shift";
                else
                    conversion = "Shift";
            }

            if (hasControl == true || hasAlt == true || hasShift == true)
                conversion = conversion + "+" + converter.ConvertToString(keyData & Keys.KeyCode);
            else
                conversion = converter.ConvertToString(keyData & Keys.KeyCode);

            return conversion;
        }

        public void showForm()
        {
            if (this.WindowState == FormWindowState.Normal)
            {
                this.WindowState = FormWindowState.Normal;
                this.StartPosition = FormStartPosition.Manual;
                this.Location = new Point(Screen.PrimaryScreen.WorkingArea.Right - this.Size.Width, Screen.PrimaryScreen.WorkingArea.Bottom - this.Size.Height);
                this.Show();
            }
            else
                this.Show();

            if (textBoxLog.TextLength != 0)
            {
                textBoxLog.SelectionStart = textBoxLog.TextLength - 1;
                textBoxLog.ScrollToCaret();
            }
        }

        private string iniGetValue(string key, string defaultValue)
        {
            return iniFile.GetValue("GPU Performance Manager", key, defaultValue);
        }

        private void iniSetValue(string key, string value)
        {
            iniFile.SetValue("GPU Performance Manager", key, value);
        }

        private void getSettingsFromIni()
        {
            file2D = iniGetValue("2DFile", String.Empty);
            file3D = iniGetValue("3DFile", String.Empty);
            textBox2D.Text = file2D;
            textBox3D.Text = file3D;

            if (Boolean.TryParse(iniGetValue("LaunchMonitoringAtStartup", "False"), out launchMonitoringAtStartup) == true)
                checkBoxMonitoringStartup.Checked = launchMonitoringAtStartup;
            else
                checkBoxMonitoringStartup.Checked = false;

            if (Boolean.TryParse(iniGetValue("OpenToSystemTray", "True"), out openToSystemTray) == true)
                checkBoxOpenToTray.Checked = openToSystemTray;
            else
                checkBoxOpenToTray.Checked = true;

            if (Boolean.TryParse(iniGetValue("CloseToSystemTray", "True"), out closeToSystemTray) == true)
                checkBoxCloseToTray.Checked = closeToSystemTray;
            else
                checkBoxCloseToTray.Checked = true;

            if (Int32.TryParse(iniGetValue("PollingRate", "10000"), out pollingRate) == true)
                textBoxPollingRate.Text = pollingRate.ToString();
            else
                textBoxPollingRate.Text = "10000";

            application3DList = iniGetValue("3DApplicationList", String.Empty).Split(';').ToList<string>();
            application3DList.RemoveAll(isStringEmpty);
            for (int i = 0; i < application3DList.Count; i++)
                listBox3DApplications.Items.Add(application3DList[i]);
            for (int i = 0; i < application3DList.Count; i++)
                application3DList[i] = application3DList[i].ToUpperInvariant();

            bool parsing = false;
            parsing = Int32.TryParse(iniGetValue("HotKeyStartMonitoring", "0"), out globalHotKeyStartMonitoringKeyData);
            if (parsing == true && globalHotKeyStartMonitoringKeyData != 0)
            {
                globalHotKeyStartMonitoring = new GlobalHotKey(this, (Keys)globalHotKeyStartMonitoringKeyData);
                textBoxHotKeyStartMonitoring.Text = convertKeysToString((Keys)globalHotKeyStartMonitoringKeyData);
            }
            else
                textBoxHotKeyStartMonitoring.Text = "Not assigned";

            parsing = Int32.TryParse(iniGetValue("HotKeyStopMonitoring", "0"), out globalHotKeyStopMonitoringKeyData);
            if (parsing == true && globalHotKeyStopMonitoringKeyData != 0)
            {
                globalHotKeyStopMonitoring = new GlobalHotKey(this, (Keys)globalHotKeyStopMonitoringKeyData);
                textBoxHotKeyStopMonitoring.Text = convertKeysToString((Keys)globalHotKeyStopMonitoringKeyData);
            }
            else
                textBoxHotKeyStopMonitoring.Text = "Not assigned";

            parsing = Int32.TryParse(iniGetValue("HotKey2D", "0"), out globalHotKey2DKeyData);
            if (parsing == true && globalHotKey2DKeyData != 0)
            {
                globalHotKey2D = new GlobalHotKey(this, (Keys)globalHotKey2DKeyData);
                textBoxHotKey2D.Text = convertKeysToString((Keys)globalHotKey2DKeyData);
            }
            else
                textBoxHotKey2D.Text = "Not assigned";

            parsing = Int32.TryParse(iniGetValue("HotKey3D", "0"), out globalHotKey3DKeyData);
            if (parsing == true && globalHotKey3DKeyData != 0)
            {
                globalHotKey3D = new GlobalHotKey(this, (Keys)globalHotKey3DKeyData);
                textBoxHotKey3D.Text = convertKeysToString((Keys)globalHotKey3DKeyData);
            }
            else
                textBoxHotKey3D.Text = "Not assigned";
        }

        private static bool isStringEmpty(string input)
        {
            return input == String.Empty;
        }

        private void textBox2D_TextChanged(object sender, EventArgs e)
        {
            if (textBox2D.Text != file2D)
            {
                file2D = textBox2D.Text;
                iniSetValue("2DFile", textBox2D.Text);
            }
        }

        private void textBox3D_TextChanged(object sender, EventArgs e)
        {
            if (textBox3D.Text != file3D)
            {
                file3D = textBox3D.Text;
                iniSetValue("3DFile", textBox3D.Text);
            }
        }

        private void textBoxPollingRate_TextChanged(object sender, EventArgs e)
        {
            int value;
            if (Int32.TryParse(textBoxPollingRate.Text, out value) == true)
            {
                if (value.ToString() != iniGetValue("PollingRate", "10000"))
                {
                    iniSetValue("PollingRate", value.ToString());
                    pollingRate = value;
                }
            }
            else
            {
                MessageBox.Show("WARNING: You have entered an invalid number. Please enter a valid integer.", "Polling rate validation", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                textBoxPollingRate.Text = "10000";
            }
        }

        private void checkBoxMonitoringStartup_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxMonitoringStartup.Checked.ToString() != iniGetValue("LaunchMonitoringAtStartup", "False"))
            {
                iniSetValue("LaunchMonitoringAtStartup", checkBoxMonitoringStartup.Checked.ToString());
                launchMonitoringAtStartup = checkBoxMonitoringStartup.Checked;
            }
        }

        private void checkBoxOpenToTray_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxOpenToTray.Checked.ToString() != iniGetValue("OpenToSystemTray", "True"))
            {
                iniSetValue("OpenToSystemTray", checkBoxOpenToTray.Checked.ToString());
                openToSystemTray = checkBoxOpenToTray.Checked;
            }
        }

        private void checkBoxCloseToTray_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxCloseToTray.Checked.ToString() != iniGetValue("CloseToSystemTray", "True"))
            {
                iniSetValue("CloseToSystemTray", checkBoxCloseToTray.Checked.ToString());
                closeToSystemTray = checkBoxCloseToTray.Checked;
            }
        }

        private void buttonBrowse2D_Click(object sender, EventArgs e)
        {
            DialogResult result = fileBrowserDialog2D.ShowDialog();
            if (result == DialogResult.OK)
                textBox2D.Text = fileBrowserDialog2D.FileName;
        }

        private void buttonBrowse3D_Click(object sender, EventArgs e)
        {
            DialogResult result = fileBrowserDialog3D.ShowDialog();
            if (result == DialogResult.OK)
                textBox3D.Text = fileBrowserDialog3D.FileName;
        }

        private void buttonStartMonitoring_Click(object sender, EventArgs e)
        {
            if (monitoringRunning == false)
            {
                signalStartMonitoring();
                launchMonitoring();
            }
        }

        private void buttonStopMonitoring_Click(object sender, EventArgs e)
        {
            if (monitoringRunning == true)
                signalStopMonitoring();
        }

        private void buttonForce2D_Click(object sender, EventArgs e)
        {
            if (monitoringRunning == true)
                signalStopMonitoring();
            load2DProfile();
        }

        private void buttonForce3D_Click(object sender, EventArgs e)
        {
            if (monitoringRunning == true)
                signalStopMonitoring();
            load3DProfile();
        }

        private void buttonAdd3D_Click(object sender, EventArgs e)
        {
            DialogResult result = fileBrowserAdd3D.ShowDialog();
            if (result == DialogResult.OK)
            {
                string executable = Path.GetFileName(fileBrowserAdd3D.FileName);
                listBox3DApplications.Items.Add(executable);
                application3DList.Add(executable.ToUpperInvariant());
                iniSetValue("3DApplicationList", String.Join(";", listBox3DApplications.Items.Cast<string>()));
            }
        }

        private void buttonRemove3D_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("Are you sure you want to remove the selected application from the 3D applications list?", "3D application removal", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
            if (result == DialogResult.Yes)
            {
                application3DList.Remove(listBox3DApplications.SelectedItem.ToString().ToUpperInvariant());
                listBox3DApplications.Items.Remove(listBox3DApplications.SelectedItem);
                iniSetValue("3DApplicationList", String.Join(";", listBox3DApplications.Items.Cast<string>()));
                buttonRemove3D.Enabled = false;
            }
        }

        private void listBox3DApplications_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listBox3DApplications.SelectedIndex != -1)
                buttonRemove3D.Enabled = true;
        }

        private void listBox3DApplications_Leave(object sender, EventArgs e)
        {
            if (buttonRemove3D.Focused != true)
            {
                buttonRemove3D.Enabled = false;
                listBox3DApplications.ClearSelected();
            }
        }

        private void GPU_Performance_Manager_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing && closeToSystemTray == true)
            {
                if (this.Visible == true)
                    this.Hide();
                e.Cancel = true;
            }
            else
                Application.Exit();
        }

        private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (this.Visible == false || this.WindowState == FormWindowState.Minimized)
                showForm();
        }

        private void contextMenuTray_Opening(object sender, CancelEventArgs e)
        {
            if (monitoringRunning == true)
            {
                toolStripStartMonitoring.Enabled = false;
                toolStripStopMonitoring.Enabled = true;
            }
            else
            {
                toolStripStartMonitoring.Enabled = true;
                toolStripStopMonitoring.Enabled = false;
            }
        }

        private void toolStripOpen_Click(object sender, EventArgs e)
        {
            if (this.Visible == false || this.WindowState == FormWindowState.Minimized)
                showForm();
        }

        private void toolStripClose_Click(object sender, EventArgs e)
        {
            unregisterHotKey(globalHotKeyStartMonitoring);
            unregisterHotKey(globalHotKeyStopMonitoring);
            unregisterHotKey(globalHotKey2D);
            unregisterHotKey(globalHotKey3D);
            Application.Exit();
        }

        private void toolStripStartMonitoring_Click(object sender, EventArgs e)
        {
            if (monitoringRunning == false)
            {
                signalStartMonitoring();
                launchMonitoring();
            }
        }

        private void toolStripStopMonitoring_Click(object sender, EventArgs e)
        {
            if (monitoringRunning == true)
                signalStopMonitoring();
        }

        private void toolStripForce2D_Click(object sender, EventArgs e)
        {
            if (monitoringRunning == true)
                signalStopMonitoring();
            load2DProfile();
        }

        private void toolStripForce3D_Click(object sender, EventArgs e)
        {
            if (monitoringRunning == true)
                signalStopMonitoring();
            load3DProfile();
        }

        private void textBoxHotKeyStartMonitoring_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.Back)
            {
                if (e.Modifiers != Keys.None &&
                    e.KeyCode != Keys.ControlKey &&
                    e.KeyCode != Keys.Menu &&
                    e.KeyCode != Keys.ShiftKey &&
                    e.KeyCode != Keys.RShiftKey &&
                    e.KeyCode != Keys.LShiftKey &&
                    e.KeyCode != Keys.LWin &&
                    e.KeyCode != Keys.RWin)
                {
                    globalHotKeyStartMonitoringKeyData = (int)e.KeyData;
                    iniSetValue("HotKeyStartMonitoring", globalHotKeyStartMonitoringKeyData.ToString());

                    unregisterHotKey(globalHotKeyStartMonitoring);
                    globalHotKeyStartMonitoring = new GlobalHotKey(this, e.KeyData);
                    validateAndRegisterHotKey(globalHotKeyStartMonitoring);

                    textBoxHotKeyStartMonitoring.Text = convertKeysToString(e.KeyData);
                }
            }
            else
            {
                globalHotKeyStartMonitoringKeyData = 0;
                iniSetValue("HotKeyStartMonitoring", "0");
                unregisterHotKey(globalHotKeyStartMonitoring);
                textBoxHotKeyStartMonitoring.Text = "Not assigned";
            }
            e.SuppressKeyPress = true;
        }

        private void textBoxHotKeyStopMonitoring_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.Back)
            {
                if (e.Modifiers != Keys.None &&
                    e.KeyCode != Keys.ControlKey &&
                    e.KeyCode != Keys.Menu &&
                    e.KeyCode != Keys.ShiftKey &&
                    e.KeyCode != Keys.RShiftKey &&
                    e.KeyCode != Keys.LShiftKey &&
                    e.KeyCode != Keys.LWin &&
                    e.KeyCode != Keys.RWin)
                {
                    globalHotKeyStopMonitoringKeyData = (int)e.KeyData;
                    iniSetValue("HotKeyStopMonitoring", globalHotKeyStopMonitoringKeyData.ToString());

                    unregisterHotKey(globalHotKeyStopMonitoring);
                    globalHotKeyStopMonitoring = new GlobalHotKey(this, e.KeyData);
                    validateAndRegisterHotKey(globalHotKeyStopMonitoring);

                    textBoxHotKeyStopMonitoring.Text = convertKeysToString(e.KeyData);
                }
            }
            else
            {
                globalHotKeyStopMonitoringKeyData = 0;
                iniSetValue("HotKeyStopMonitoring", "0");
                unregisterHotKey(globalHotKeyStopMonitoring);
                textBoxHotKeyStopMonitoring.Text = "Not assigned";
            }
            e.SuppressKeyPress = true;
        }

        private void textBoxHotKey2D_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.Back)
            {
                if (e.Modifiers != Keys.None &&
                    e.KeyCode != Keys.ControlKey &&
                    e.KeyCode != Keys.Menu &&
                    e.KeyCode != Keys.ShiftKey &&
                    e.KeyCode != Keys.RShiftKey &&
                    e.KeyCode != Keys.LShiftKey &&
                    e.KeyCode != Keys.LWin &&
                    e.KeyCode != Keys.RWin)
                {
                    globalHotKey2DKeyData = (int)e.KeyData;
                    iniSetValue("HotKey2D", globalHotKey2DKeyData.ToString());

                    unregisterHotKey(globalHotKey2D);
                    globalHotKey2D = new GlobalHotKey(this, e.KeyData);
                    validateAndRegisterHotKey(globalHotKey2D);

                    textBoxHotKey2D.Text = convertKeysToString(e.KeyData);
                }
            }
            else
            {
                globalHotKey2DKeyData = 0;
                iniSetValue("HotKey2D", "0");
                unregisterHotKey(globalHotKey2D);
                textBoxHotKey2D.Text = "Not assigned";
            }
            e.SuppressKeyPress = true;
        }

        private void textBoxHotKey3D_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.Back)
            {
                if (e.Modifiers != Keys.None &&
                    e.KeyCode != Keys.ControlKey &&
                    e.KeyCode != Keys.Menu &&
                    e.KeyCode != Keys.ShiftKey &&
                    e.KeyCode != Keys.RShiftKey &&
                    e.KeyCode != Keys.LShiftKey &&
                    e.KeyCode != Keys.LWin &&
                    e.KeyCode != Keys.RWin)
                {
                    globalHotKey3DKeyData = (int)e.KeyData;
                    iniSetValue("HotKey3D", globalHotKey3DKeyData.ToString());

                    unregisterHotKey(globalHotKey3D);
                    globalHotKey3D = new GlobalHotKey(this, e.KeyData);
                    validateAndRegisterHotKey(globalHotKey3D);

                    textBoxHotKey3D.Text = convertKeysToString(e.KeyData);
                }
            }
            else
            {
                globalHotKey3DKeyData = 0;
                iniSetValue("HotKey3D", "0");
                unregisterHotKey(globalHotKey3D);
                textBoxHotKey3D.Text = "Not assigned";
            }
            e.SuppressKeyPress = true;
        }

        private void textBoxHotKeyStartMonitoring_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = true;
        }

        private void textBoxHotKeyStopMonitoring_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = true;
        }

        private void textBoxHotKey2D_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = true;
        }

        private void textBoxHotKey3D_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = true;
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WindowsHotKeyConstants.WM_HOTKEY_MSG_ID)
            {
                if (globalHotKeyStartMonitoring != null)
                {
                    if ((int)m.WParam == globalHotKeyStartMonitoring.ID)
                    {
                        if (monitoringRunning == false)
                        {
                            signalStartMonitoring();
                            launchMonitoring();
                        }
                    }
                }
                if (globalHotKeyStopMonitoring != null)
                {
                    if ((int)m.WParam == globalHotKeyStopMonitoring.ID)
                    {
                        if (monitoringRunning == true)
                            signalStopMonitoring();
                    }
                }
                if (globalHotKey2D != null)
                {
                    if ((int)m.WParam == globalHotKey2D.ID)
                    {
                        if (monitoringRunning == true)
                            signalStopMonitoring();
                        load2DProfile();
                    }
                }
                if (globalHotKey3D != null)
                {
                    if ((int)m.WParam == globalHotKey3D.ID)
                    {
                        if (monitoringRunning == true)
                            signalStopMonitoring();
                        load3DProfile();
                    }
                }
            }
            base.WndProc(ref m);
        }

        private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
        {
            switch (e.Mode)
            {
                case PowerModes.Suspend:
                    if (monitoringRunning == true)
                        signalStopMonitoring();
                    load2DProfile();
                    break;
                case PowerModes.Resume:
                    if (monitoringRunning == false)
                    {
                        signalStartMonitoring();
                        launchMonitoring();
                    }
                    break;
            }
        }
    }
}
